/**
*	@file Affects.cpp
*
*	@brief this header file is to implement Affect table
*
*	@author li yuchen & lan ziquan
*
*	@date 1/28/2011
*/

#include "Affects.h"
#include <ppl.h>
using namespace Concurrency;

vector<AssignSet>	Affects::affects_table_;
vector<AssignSet>	Affects::affects_table_t_;
AssignSet			Affects::affects_has_a0_cache_;
AssignSet			Affects::affects_has_0a_cache_;
AssignSet			Affects::affects_has_a0_;
AssignSet			Affects::affects_has_0a_;
bool				Affects::affects_has_00_;
bool				Affects::affects_has_00_cache_;

vector<AssignSet>	Affects::affect_star_cache_;
vector<AssignSet>	Affects::affect_star_cache_hit_;

static VarIdx ModifiesTargetIdx(StmtNum stmt_num, VarSet& modifies_target)
{
	for( int i = 0; i < modifies_target.size(); i++ )
		if( modifies_target[i] )
			if( Modifies::IsModifiesS(stmt_num, i+1) )
				return i+1;
	return 0;
}

static void CallModifiesTarget(StmtNum stmt_num, VarSet& modifies_target, VarSet& result_o)
{
	for( int i = 0; i < modifies_target.size(); i++ )
		if( modifies_target[i] )
			if( Modifies::IsModifiesS(stmt_num, i+1) )
				result_o[i] = false;
}

void Affects::RebuildAffects()
{
	affects_table_.resize(StmtTable::GetSizeAssign());
	affects_table_t_.resize(StmtTable::GetSizeAssign());
	affect_star_cache_.resize(StmtTable::GetSizeAssign());
	affect_star_cache_hit_.resize(StmtTable::GetSizeAssign());
	for( int i = 0; i < StmtTable::GetSizeAssign(); i++ )
	{
		affects_table_[i].resize(StmtTable::GetSizeAssign());
		affects_table_t_[i].resize(StmtTable::GetSizeAssign());
		affect_star_cache_[i].resize(StmtTable::GetSizeAssign());
		affect_star_cache_hit_[i].resize(StmtTable::GetSizeAssign());
	}
	affects_has_a0_cache_.resize(StmtTable::GetSizeAssign());
	affects_has_0a_cache_.resize(StmtTable::GetSizeAssign());
	affects_has_a0_.resize(StmtTable::GetSizeAssign());
	affects_has_0a_.resize(StmtTable::GetSizeAssign());
	affects_has_00_ = false;
	affects_has_00_cache_ = false;

}

AssignSet& Affects::GetAffectsRight(AssignNum assign_num_left)
{
	/**YUCHEN added **/ QueryThread::GetLockAffectsRight();
	
	if( affects_has_a0_cache_[assign_num_left - 1] ){
		/**YUCHEN added **/ QueryThread::ReleaseLockAffectsRight();
		return affects_table_[assign_num_left - 1];
	}

	// BLKNODE approach
	AssignSet result(StmtTable::GetSizeAssign(), false);
	BlkSet visited(BlkTable::GetSize(), false);
	BlkSet frontier(BlkTable::GetSize(), false);
	BlkSet frontier_minus_visited;
	StmtNum stmt_num_last_mod = BlkTable::GetBlkNode(StmtTable::GetStmtBlkNode(StmtTable::GetAssignTNode(assign_num_left)->stmt_num)->blk_idx)
		->last_mod[StmtTable::GetAssignTNode(assign_num_left)->child->value - 1];
	// case of last modified
	if( stmt_num_last_mod == StmtTable::GetAssignTNode(assign_num_left)->stmt_num )
	{
		frontier = BlkTable::GetNextBlkRight(StmtTable::GetStmtBlkNode(StmtTable::GetAssignTNode(assign_num_left)->stmt_num)->blk_idx);
		for( StmtNum i = StmtTable::GetAssignTNode(assign_num_left)->stmt_num + 1;
			i <= StmtTable::GetStmtBlkNode(StmtTable::GetAssignTNode(assign_num_left)->stmt_num)->stmt_num_end;
			i++)
		{
			if( Uses::IsUsesS(i, StmtTable::GetAssignTNode(assign_num_left)->child->value) )
				result[StmtTable::GetStmtTNode(i)->value - 1] = true;
		}
	}
	// case of not last modified
	else
	{
		for( StmtNum i = StmtTable::GetAssignTNode(assign_num_left)->stmt_num + 1; i <= stmt_num_last_mod; i++)
		{
			if( Uses::IsUsesS(i, StmtTable::GetAssignTNode(assign_num_left)->child->value) )
				result[StmtTable::GetStmtTNode(i)->value - 1] = true;
			if( Modifies::IsModifiesS(i, StmtTable::GetAssignTNode(assign_num_left)->child->value) )
				break;
		}
	}
	do
	{
		frontier_minus_visited = LogicMinus<BlkSet>(frontier,visited);
		visited = LogicOR<BlkSet>(visited,frontier);
		frontier.clear();
		frontier.resize(BlkTable::GetSize(), false);
		for( int i = 0; i < BlkTable::GetSize(); i++ )
		{
			if( frontier_minus_visited[i] )
			{
				if( BlkTable::GetBlkNode(i+1)->blk_type == ASSIGN_TYPE )
				{
					for( int j = 0; j < BlkTable::GetBlkNode(i+1)->use_bef_mod[StmtTable::GetAssignTNode(assign_num_left)->child->value - 1].size(); j++ )
						result[StmtTable::GetStmtTNode(BlkTable::GetBlkNode(i+1)->use_bef_mod[StmtTable::GetAssignTNode(assign_num_left)->child->value - 1][j])->value - 1] = true;
				}
				if( (BlkTable::GetBlkNode(i+1)->blk_type == ASSIGN_TYPE && BlkTable::GetBlkNode(i+1)->last_mod[StmtTable::GetAssignTNode(assign_num_left)->child->value - 1]) ||
					(BlkTable::GetBlkNode(i+1)->blk_type == CALL_TYPE && Modifies::IsModifiesS(BlkTable::GetBlkNode(i+1)->stmt_num_start, StmtTable::GetAssignTNode(assign_num_left)->child->value)) )
					frontier_minus_visited[i] = false;
			}
		}
		for( int i = 0; i < BlkTable::GetSize(); i++ )
		{
			if( frontier_minus_visited[i] )
				frontier = LogicOR<BlkSet>(frontier, BlkTable::GetNextBlkRight(i+1));
		}
	}while( IsAny<BlkSet>(frontier_minus_visited) );

	// Normal approach
	//AssignSet result(StmtTable::GetSizeAssign(), false);
	//StmtSet visited(StmtTable::GetSize(), false);
	//StmtSet frontier(StmtTable::GetSize(), false);
	//StmtSet frontier_minus_visited;

	//frontier = Next::GetNextRight(StmtTable::GetAssignTNode(assign_num_left)->stmt_num);
	//do
	//{
	//	frontier_minus_visited = LogicMinus<StmtSet>(frontier,visited);
	//	visited = LogicOR<StmtSet>(visited,frontier);
	//	frontier.clear();
	//	frontier.resize(StmtTable::GetSize(),false);
	//	for( int i = 0; i < StmtTable::GetSize(); i++ )
	//	{
	//		if( frontier_minus_visited[i] )
	//		{
	//			if( StmtTable::GetStmtTNode(i+1)->type == ASSIGN_TYPE &&
	//				Uses::IsUsesS(i+1,StmtTable::GetAssignTNode(assign_num_left)->child->value))
	//				result[StmtTable::GetStmtTNode(i+1)->value - 1] = true;
	//			if( ( StmtTable::GetStmtTNode(i+1)->type == ASSIGN_TYPE || 
	//					StmtTable::GetStmtTNode(i+1)->type == CALL_TYPE ) &&
	//				ModifiesTargetIdx(i+1,Modifies::GetModifiesS(StmtTable::GetAssignTNode(assign_num_left)->stmt_num)) )
	//				frontier_minus_visited[i] = false;
	//		}
	//	}

	//	for( int i = 0; i < StmtTable::GetSize(); i++ )
	//	{
	//		if( frontier_minus_visited[i] )
	//			frontier = LogicOR<StmtSet>(frontier, Next::GetNextRight(i+1));
	//	}
	//}
	//while( IsAny<StmtSet>(frontier_minus_visited) );
	
	affects_table_[assign_num_left - 1] = result;
	affects_has_a0_[assign_num_left - 1] = IsAny<AssignSet>(result);
	affects_has_a0_cache_[assign_num_left - 1] = true;
	if( !affects_has_00_cache_ )
	{
		if( affects_has_a0_[assign_num_left - 1] )
		{
			affects_has_00_ = true;
			affects_has_00_cache_ = true;
		}
		else if( IsAll<AssignSet>(affects_has_a0_cache_) )
		{
			affects_has_00_ = false;
			affects_has_00_cache_ = true;
		}
	}
	/**YUCHEN added **/ QueryThread::ReleaseLockAffectsRight();
	return affects_table_[assign_num_left - 1];
}

AssignSet& Affects::GetAffectsLeft(AssignNum assign_num_right)
{
	/**YUCHEN added **/ QueryThread::GetLockAffectsLeft();

	if( affects_has_0a_cache_[assign_num_right - 1] ){
		/**YUCHEN added **/ QueryThread::ReleaseLockAffectsLeft();
		return affects_table_t_[assign_num_right - 1];
	}

	// BlkNode approach
	stack<BlkIdx> stack_frontier;
	stack<BlkSet> stack_path;
	stack<VarSet> stack_not_affects;

	AssignSet result(StmtTable::GetSizeAssign(), false);
	VarSet current_not_affects = Uses::GetUsesS(StmtTable::GetAssignTNode(assign_num_right)->stmt_num);
	for( StmtNum i = StmtTable::GetAssignTNode(assign_num_right)->stmt_num - 1;
		i >= StmtTable::GetStmtBlkNode(StmtTable::GetAssignTNode(assign_num_right)->stmt_num)->stmt_num_start; 
		i-- )
	{
		for( int j = 0; j < VarTable::GetSize(); j++ )
		{
			if( current_not_affects[j] && Modifies::IsModifiesS(i, j+1) )
			{
				current_not_affects[j] = false;
				result[StmtTable::GetStmtTNode(i)->value - 1] = true;
				break;
			}
		}
		if( IsNone<VarSet>(current_not_affects) ) break;
	}
	BlkSet current_frontiers = BlkTable::GetNextBlkLeft(StmtTable::GetStmtBlkNode(StmtTable::GetAssignTNode(assign_num_right)->stmt_num)->blk_idx);
	BlkSet current_path(StmtTable::GetSize(), false);
	for( int i = 0; i < BlkTable::GetSize(); i++ )
	{
		if( current_frontiers[i] && IsAny<VarSet>(current_not_affects) )
		{
			stack_frontier.push(i+1);
			stack_path.push(current_path);
			stack_not_affects.push(current_not_affects);
		}
	}

	while( !stack_frontier.empty() )
	{
		current_not_affects = stack_not_affects.top();
		if( BlkTable::GetBlkNode(stack_frontier.top())->blk_type == ASSIGN_TYPE )
		{
			for( int i = 0; i < VarTable::GetSize(); i++ )
			{
				if( current_not_affects[i] && BlkTable::GetBlkNode(stack_frontier.top())->last_mod[i] )
				{
					current_not_affects[i] = false;
					result[StmtTable::GetStmtTNode(BlkTable::GetBlkNode(stack_frontier.top())->last_mod[i])->value - 1] = true;
				}
			}
			if( IsNone<VarSet>(current_not_affects) )
			{
				stack_frontier.pop();
				stack_path.pop();
				stack_not_affects.pop();
				continue;
			}
		}
		else if( BlkTable::GetBlkNode(stack_frontier.top())->blk_type == CALL_TYPE )
		{
			CallModifiesTarget(BlkTable::GetBlkNode(stack_frontier.top())->stmt_num_start,Uses::GetUsesS(StmtTable::GetAssignTNode(assign_num_right)->stmt_num),current_not_affects);
			if( IsNone<StmtSet>(current_not_affects) )
			{
				stack_frontier.pop();
				stack_path.pop();
				stack_not_affects.pop();
				continue;
			}
		}
		current_frontiers = BlkTable::GetNextBlkLeft(stack_frontier.top());
		current_path = stack_path.top();
		current_path[stack_frontier.top() - 1] = true;
		BlkSet frontier_minus_visited = LogicMinus<BlkSet>(current_frontiers, current_path);

		stack_frontier.pop();
		stack_path.pop();
		stack_not_affects.pop();

		for( int i = 0; i < BlkTable::GetSize(); i++ )
		{
			if( frontier_minus_visited[i] )
			{
				stack_frontier.push(i+1);
				stack_path.push(current_path);
				stack_not_affects.push(current_not_affects);
			}
		}
	}

	// Normal approach
	//stack<StmtNum> stack_frontier;
	//stack<StmtSet> stack_path;
	//stack<VarSet> stack_not_affects;

	//AssignSet result(StmtTable::GetSizeAssign(), false);
	//VarSet current_not_affects = Uses::GetUsesS(StmtTable::GetAssignTNode(assign_num_right)->stmt_num);
	//StmtSet current_frontiers = Next::GetNextLeft(StmtTable::GetAssignTNode(assign_num_right)->stmt_num);
	//StmtSet current_path(StmtTable::GetSize(), false);
	//for( int i = 0; i < StmtTable::GetSize(); i++ )
	//{
	//	if( current_frontiers[i] )
	//	{
	//		stack_frontier.push(i+1);
	//		stack_path.push(current_path);
	//		stack_not_affects.push(current_not_affects);
	//	}
	//}

	//while( !stack_frontier.empty() )
	//{
	//	current_not_affects = stack_not_affects.top();
	//	if( StmtTable::GetStmtTNode(stack_frontier.top())->type == ASSIGN_TYPE )
	//	{
	//		VarIdx target_idx = ModifiesTargetIdx(stack_frontier.top(),Uses::GetUsesS(StmtTable::GetAssignTNode(assign_num_right)->stmt_num));
	//		if( target_idx != 0 && stack_not_affects.top()[target_idx - 1] )
	//		{
	//			current_not_affects[target_idx - 1] = false;
	//			result[StmtTable::GetStmtTNode(stack_frontier.top())->value - 1] = true;
	//			if( IsNone<VarSet>(current_not_affects) )
	//			{
	//				stack_frontier.pop();
	//				stack_path.pop();
	//				stack_not_affects.pop();
	//				continue;
	//			}
	//		}
	//	}
	//	else if( StmtTable::GetStmtTNode(stack_frontier.top())->type == CALL_TYPE )
	//	{
	//		CallModifiesTarget(stack_frontier.top(),Uses::GetUsesS(StmtTable::GetAssignTNode(assign_num_right)->stmt_num),current_not_affects);
	//		if( IsNone<StmtSet>(current_not_affects) )
	//		{
	//			stack_frontier.pop();
	//			stack_path.pop();
	//			stack_not_affects.pop();
	//			continue;
	//		}
	//	}
	//	current_frontiers = Next::GetNextLeft(stack_frontier.top());
	//	current_path = stack_path.top();
	//	current_path[stack_frontier.top() - 1] = true;
	//	StmtSet frontier_minus_visited = LogicMinus<StmtSet>(current_frontiers, current_path);

	//	stack_frontier.pop();
	//	stack_path.pop();
	//	stack_not_affects.pop();

	//	for( int i = 0; i < StmtTable::GetSize(); i++ )
	//	{
	//		if( frontier_minus_visited[i] )
	//		{
	//			stack_frontier.push(i+1);
	//			stack_path.push(current_path);
	//			stack_not_affects.push(current_not_affects);
	//		}
	//	}
	//}

	affects_table_t_[assign_num_right - 1] = result;
	affects_has_0a_[assign_num_right - 1] = IsAny<AssignSet>(result);
	affects_has_0a_cache_[assign_num_right - 1] = true;
	if( !affects_has_00_cache_ )
	{
		if( affects_has_0a_[assign_num_right - 1] )
		{
			affects_has_00_ = true;
			affects_has_00_cache_ = true;
		}
		else if( IsAll<AssignSet>(affects_has_0a_cache_) )
		{
			affects_has_00_ = false;
			affects_has_00_cache_ = true;
		}
	}
	/**YUCHEN added **/ QueryThread::ReleaseLockAffectsLeft();
	return affects_table_t_[assign_num_right - 1];
}

bool Affects::IsAffects(StmtNum assign_num_left, StmtNum assign_num_right)
{
	if( assign_num_left > StmtTable::GetSize() ||
		assign_num_right > StmtTable::GetSize() ||
		(assign_num_left != 0 && StmtTable::GetStmtTNode(assign_num_left)->type != ASSIGN_TYPE) ||
		(assign_num_right != 0 && StmtTable::GetStmtTNode(assign_num_right)->type != ASSIGN_TYPE) )
		return false;
	if( assign_num_left != 0 && assign_num_right != 0 &&
		!Next::IsNextAdv(assign_num_left, assign_num_right) )
		return false;
	if( assign_num_left == 0 && assign_num_right == 0 )
	{
		for( int i = 0; i < StmtTable::GetSizeAssign(); i++ )
		{
			if( affects_has_00_cache_ ) break;
			GetAffectsRight(i+1);
		}
		return affects_has_00_;
	}
	if( assign_num_left == 0 )
	{
		if( affects_has_0a_cache_[StmtTable::GetStmtTNode(assign_num_right)->value - 1] )
			return affects_has_0a_[StmtTable::GetStmtTNode(assign_num_right)->value - 1];
		GetAffectsLeft(StmtTable::GetStmtTNode(assign_num_right)->value);
		return affects_has_0a_[StmtTable::GetStmtTNode(assign_num_right)->value - 1];
	}
	if( assign_num_right == 0 )
	{
		if( affects_has_a0_cache_[StmtTable::GetStmtTNode(assign_num_left)->value - 1] )
			return affects_has_a0_[StmtTable::GetStmtTNode(assign_num_left)->value - 1];
		GetAffectsRight(StmtTable::GetStmtTNode(assign_num_left)->value);
		return affects_has_a0_[StmtTable::GetStmtTNode(assign_num_left)->value - 1];
	}
	if( affects_has_a0_cache_[StmtTable::GetStmtTNode(assign_num_left)->value - 1] )
		return affects_table_[StmtTable::GetStmtTNode(assign_num_left)->value - 1][StmtTable::GetStmtTNode(assign_num_right)->value - 1];
	if( affects_has_0a_cache_[StmtTable::GetStmtTNode(assign_num_right)->value - 1] )
		return affects_table_t_[StmtTable::GetStmtTNode(assign_num_right)->value - 1][StmtTable::GetStmtTNode(assign_num_left)->value - 1];
	AssignSet& result = GetAffectsRight(StmtTable::GetStmtTNode(assign_num_left)->value);
	return result[StmtTable::GetStmtTNode(assign_num_right)->value - 1];
}

/************************************* for usage of IsAffectsAdv *******************************************/
/**
* @brief merge two set to set_a and if there is any changes return true
*/
static bool MergeAssignSet(AssignSet& set_a, AssignSet& set_b){
	bool changed = false;
	parallel_for_each(concurrency_counter.begin(), concurrency_counter.begin() + set_b.size(), [&](int i){
		if(set_b[i]){
			if(!set_a[i]){
				set_a[i] = true;
				changed = true;
			}
		}
	});
	return changed;
}

static bool CheckAffectConnection(AssignSet& set_a,  AssignSet& set_b){
	for(int i = 0; i < set_a.size();i++){
		if(set_a[i] && set_b[i]) return true;
	}
	return false;
}

bool Affects::IsAffectsAdv(StmtNum assign_num_left, StmtNum assign_num_right){
	// check if Affect(a,b) hold
	if(assign_num_left > StmtTable::GetSize() || assign_num_right > StmtTable::GetSize()) return false;
	if(StmtTable::GetStmtTNode(assign_num_left)->type != ASSIGN_TYPE || 
		StmtTable::GetStmtTNode(assign_num_right)->type != ASSIGN_TYPE) return false;
	if(Affects::IsAffects(assign_num_left,assign_num_right)) return true;

	/** may need to change for the next iter */
	if(StmtTable::GetProcIdx(assign_num_left) != StmtTable::GetProcIdx(assign_num_right)) return false;

	AssignNum x = StmtTable::GetStmtTNode(assign_num_left)->value;
	AssignNum y = StmtTable::GetStmtTNode(assign_num_right)->value;
	if(x == -1 || y == -1) return false;
	// if it has already been cached
	if(AffectAdvCacheModified(x,y)) return AccessAffectsAdvCache(x,y,false,false);


	/* check all false condition */
	AssignSet affected_assigment_up = GetAffectsRight(x);
	AssignSet affected_assigment_down = GetAffectsLeft(y);
	bool all_false_up = !Affects::affects_has_a0_[x-1];
	bool all_false_down = !Affects::affects_has_0a_[y-1];
	if(all_false_up && all_false_down){
		CacheAffectAdv(affected_assigment_up,x,true,true);
		CacheAffectAdv(affected_assigment_down,y,false,true);
		return false;
	}else if(all_false_up){
		CacheAffectAdv(affected_assigment_up,x,true,true);
		CacheAffectAdv(affected_assigment_down,y,false,false);
		return false;
	}else if(all_false_down){
		CacheAffectAdv(affected_assigment_up,x,true,false);
		CacheAffectAdv(affected_assigment_down,y,false,true);
		return false;
	}

	AssignSet visited_up((affected_assigment_up).size(),false);
	AssignSet visited_down((affected_assigment_down).size(),false);

	if(CheckAffectConnection((affected_assigment_up),(affected_assigment_down))){
		CacheAffectAdv(affected_assigment_up,x,true,false);
		CacheAffectAdv(affected_assigment_down,y,false,false);
		return true;
	}
	
	bool changed_up = true;
	bool changed_down = true;
	while(1){
		bool temp_up = false;
		bool temp_down = false;
		for(int i = 0; i < StmtTable::GetSizeAssign(); i++){
			if(changed_up){
				if((affected_assigment_up)[i] && visited_up[i] == false){
					AssignSet temp = GetAffectsRight(i+1); //affect_range_table_[i];
					if(temp_up) MergeAssignSet(affected_assigment_up,temp);
					else temp_up = MergeAssignSet(affected_assigment_up,temp);
					visited_up[i] = true;
				}
			}
			if(changed_down){
				if((affected_assigment_down)[i] && visited_down[i] == false){
					AssignSet temp = GetAffectsLeft(i+1); //affect_range_table_t_[i];
					if(temp_down) MergeAssignSet(affected_assigment_down,temp);
					else temp_down = MergeAssignSet(affected_assigment_down,temp);
					visited_down[i] = true;
				}
			}
		}
		if(CheckAffectConnection(affected_assigment_up,affected_assigment_down)){
			CacheAffectAdv(affected_assigment_up,x,true,false);
			CacheAffectAdv(affected_assigment_down,y,false,false);
			return true;
		}
		if(!temp_up) changed_up = false;
		if(!temp_down) changed_down = false;
		if((!changed_up)&&(!changed_down)) break;
	}

	CacheAffectAdv(affected_assigment_up,x,true,true);
	CacheAffectAdv(affected_assigment_down,y,false,true);
	return false;
}

bool Affects::AccessAffectsAdvCache(AssignNum assign_left, AssignNum assign_right, bool value, bool set_cache){
	
	if(set_cache){
		//QueryThread::GetLockAffects();
		affect_star_cache_[assign_left-1][assign_right-1] = value;
		affect_star_cache_hit_[assign_left-1][assign_right-1] = true;
		//QueryThread::ReleaseLockAffects();
		return true;
	}
	return affect_star_cache_[assign_left-1][assign_right-1];
	// need to release lock
}

bool Affects::AffectAdvCacheModified(AssignNum assign_left, AssignNum assign_right){
	//QueryThread::GetLockAffects();
	bool result = affect_star_cache_hit_[assign_left-1][assign_right-1];
	//QueryThread::ReleaseLockAffects();
	return result;
}

void Affects::CacheAffectAdv(AssignSet& set, AssignNum index, bool is_row, bool is_complete){
	if(is_complete){
		//QueryThread::GetLockAffects();
		if(is_row){
			affect_star_cache_[index-1] = set;
			for(int i = 0; i < set.size(); i++) affect_star_cache_hit_[index-1][i] = true;
		}else{
			for(int i = 0; i < set.size(); i++){
				affect_star_cache_[i][index-1] = set[i];
				affect_star_cache_hit_[i][index-1] = true;
			}
		}
		//QueryThread::ReleaseLockAffects();
	}
	else{
		if(is_row){
			for(int i = 0; i < set.size(); i++)
				if(set[i]) AccessAffectsAdvCache(index,i+1,true,true);
		}
		else{
			for(int i = 0; i < set.size(); i++)
				if(set[i]) AccessAffectsAdvCache(i+1,index,true,true);
		}
	}
}

/************************************************ affect star end *************************************/

string Affects::ToString(){
	stringstream ss;
	ss << "Affects : [" << affects_has_00_cache_ << "] : " << affects_has_00_ << endl;

	for( int i = 0; i < StmtTable::GetSizeAssign(); i++ )
	{
		ss << StmtTable::GetAssignTNode(i+1)->stmt_num << " : [" << affects_has_a0_cache_[i] << "]";
		if( affects_has_a0_cache_[i] )
		{
			for( int j = 0; j < StmtTable::GetSizeAssign(); j++ )
				ss << " " << affects_table_[i][j];
		}
		ss << endl;
	}

	ss<< endl << endl;

	for( int i = 0; i < StmtTable::GetSizeAssign(); i++ )
	{
		ss << StmtTable::GetAssignTNode(i+1)->stmt_num << " : [" << affects_has_0a_cache_[i] << "]";
		if( affects_has_0a_cache_[i] )
		{
			for( int j = 0; j < StmtTable::GetSizeAssign(); j++ )
				ss << " " << affects_table_t_[i][j];
		}
		ss << endl;
	}

	ss<< endl << endl;

	for( int i = 0; i < StmtTable::GetSizeAssign(); i++ )
	{
		ss << StmtTable::GetAssignTNode(i+1)->stmt_num << " : ";
		for( int j = 0; j < StmtTable::GetSizeAssign(); j++ )
		{
			if( affect_star_cache_hit_[i][j] )
				ss << " " << affect_star_cache_[i][j];
			else
				ss << " _";
		}
		ss << endl;
	}

	return ss.str();
}
